#include <stdlib.h>
#include <string.h>
#include <directfb.h>

#include "dtk_types.h"
#include "dtk.h"
#include "dtk_debug.h"
#include "dtk_priv.h"

static DTKContext* g_ctx = NULL;

DTKInitError dtk_init (int *argc, char***argv)
{
    DFBResult err = DFB_OK;
    DFBSurfaceDescription dsc;

    if (g_ctx == NULL)
    {
        g_ctx = (DTKContext*) malloc (sizeof(DTKContext));
        g_ctx->is_initialized = DTK_FALSE;
    }

    if (g_ctx->is_initialized)
    {
        return DTK_INIT_SUCCESS;
    }

    memset (g_ctx, 0, sizeof(DTKContext));
    
    err = DirectFBInit (argc, argv);
    if (err != DFB_OK)
    {
        dtk_release();
        return DTK_INIT_ERROR_INTERNAL;
    }

    err = DirectFBCreate (&g_ctx->dfb);
    if (err != DFB_OK)
    {
        dtk_release();
        return DTK_INIT_ERROR_INTERNAL;
    }

    err = g_ctx->dfb->GetDisplayLayer(g_ctx->dfb, 
                        DLID_PRIMARY, &g_ctx->default_layer);
    if (err != DFB_OK)
    {
        dtk_release();
        return DTK_INIT_ERROR_INTERNAL;
    }

    dsc.flags = DSDESC_CAPS;
    dsc.caps = DSCAPS_PRIMARY;//DSCAPS_PRIMARY | DSCAPS_FLIPPING;
    err = g_ctx->dfb->CreateSurface (g_ctx->dfb, &dsc, &g_ctx->default_primary);
    if (err != DFB_OK)
    {
        dtk_release();
        return DTK_INIT_ERROR_INTERNAL;
    }

    err = g_ctx->dfb->CreateEventBuffer(g_ctx->dfb, &g_ctx->default_eventbuffer);
    if (err != DFB_OK)
    {
        DirectFBError ("window_new:IDirectFBWindow::AttachEventBuffer() failed",
                    err);
        dtk_release();
        return DTK_INIT_ERROR_INTERNAL;
    }

    g_ctx->clock = dtk_mc_create();
    g_ctx->signal_manager = dtk_sm_create();

    g_ctx->default_primary->GetSize (g_ctx->default_primary,
                        &g_ctx->screen_width,
                        &g_ctx->screen_height); 

    g_ctx->is_initialized = DTK_TRUE;
    return DTK_INIT_SUCCESS;
}

DBoolean dtk_release ()
{
    if (g_ctx == NULL)
    {
        return DTK_FALSE;
    }

    if (g_ctx->default_eventbuffer)
    {
        g_ctx->default_eventbuffer->Release (g_ctx->default_eventbuffer);
        g_ctx->default_eventbuffer = NULL;
    }

    if (g_ctx->default_primary)
    {
        g_ctx->default_primary->Release(g_ctx->default_primary);
        g_ctx->default_layer = NULL;
    }

    if (g_ctx->default_layer)
    {
        g_ctx->default_layer->Release (g_ctx->default_layer);
        g_ctx->default_layer = NULL;
    }

    if (g_ctx->dfb)
    {
        g_ctx->dfb->Release(g_ctx->dfb);
        g_ctx->dfb = NULL;
    }

    if (g_ctx->stage)
    {
        dtk_actor_finalize(g_ctx->stage);
    }

    if (g_ctx->clock)
    {
        dtk_mc_release(g_ctx->clock);
    }

    if (g_ctx->signal_manager)
    {
        dtk_sm_release(g_ctx->signal_manager);
    }

    g_ctx->is_initialized = DTK_FALSE;

    free (g_ctx);
    g_ctx = NULL;
    return DTK_TRUE;
}

DTKContext* dtk_get_context()
{
    if (g_ctx == NULL || g_ctx->is_initialized == DTK_FALSE)
    {
        return NULL;
    }

    return g_ctx;
}

DBoolean dtk_set_stage (DTKActor* stage)
{
    if (g_ctx == NULL || g_ctx->is_initialized == DTK_FALSE)
    {
        return DTK_FALSE;
    }
    g_ctx->stage = stage;
    return DTK_TRUE;
}

DTKActor* dtk_get_default_stage ()
{
    if (g_ctx == NULL || g_ctx->is_initialized == DTK_FALSE)
    {
        return DTK_FALSE;
    }
    return g_ctx->stage;
}

IDirectFB* dtk_get_dfb()
{
    if (g_ctx == NULL || g_ctx->is_initialized == DTK_FALSE)
    {
        return NULL;
    }
    return g_ctx->dfb;    
}

DTKMasterClock* dtk_get_default_master_clock()
{
    DTK_ASSERT(g_ctx->clock != NULL);
    return g_ctx->clock;
}

DTKSignalManager* dtk_get_default_signal_manager()
{
    DTK_ASSERT(g_ctx->signal_manager != NULL);
    return g_ctx->signal_manager;
}

IDirectFBDisplayLayer* dtk_get_default_layer()
{
    if (g_ctx == NULL || g_ctx->is_initialized == DTK_FALSE)
    {
        return NULL;
    }
    return g_ctx->default_layer;
}

IDirectFBSurface* dtk_get_default_primary()
{
    if (g_ctx == NULL || g_ctx->is_initialized == DTK_FALSE)
    {
        return NULL;
    }

    return g_ctx->default_primary;
}

IDirectFBEventBuffer* dtk_get_default_eventbuffer()
{
    if (g_ctx == NULL || g_ctx->is_initialized == DTK_FALSE)
    {
        return NULL;
    }

    return g_ctx->default_eventbuffer;
}

DBoolean dtk_get_screen_size(DInt* width, DInt* height)
{
    if (g_ctx == NULL || g_ctx->is_initialized == DTK_FALSE)
    {
        return DTK_FALSE;
    }

    if (width)
        *width = g_ctx->screen_width;

    if (height)
        *height = g_ctx->screen_height;

    return DTK_TRUE;
}

DBoolean dtk_is_initialized(void)
{
    if (g_ctx == NULL)
    {
        return DTK_FALSE;
    }

    return g_ctx->is_initialized;
}

void dtk_loop(void)
{
    if (g_ctx->stage == NULL)
    {
        return;
    }
    dtk_event_loop(30);
    return;
}
